package com.zhihuishu.micro.course.service.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;

import org.apache.commons.lang3.math.NumberUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import redis.clients.jedis.Jedis;
import redis.clients.jedis.Pipeline;

import com.able.openapi.createCourse.IOnlineExamForCreateCourseService;
import com.able.openapi.createCourse.dto.ExamCourseDto;
import com.github.abel533.mapper.Mapper;
import com.google.common.collect.Sets;
import com.zhihuishu.micro.course.dao.ChapterMapper;
import com.zhihuishu.micro.course.dao.LessonMapper;
import com.zhihuishu.micro.course.dao.LessonVideoMapper;
import com.zhihuishu.micro.course.dto.ChapterDto;
import com.zhihuishu.micro.course.helper.LogModule;
import com.zhihuishu.micro.course.helper.RedisKeyHelper;
import com.zhihuishu.micro.course.helper.RemoteLogHelper;
import com.zhihuishu.micro.course.model.Chapter;
import com.zhihuishu.micro.course.model.Lesson;
import com.zhihuishu.micro.course.model.LessonVideo;
import com.zhihuishu.micro.course.service.ChapterService;
import com.zhihuishu.micro.course.service.CourseBuildService;
import com.zhihuishu.micro.course.service.CourseService;
import com.zhihuishu.toolkit.helper.BeanHelper;
import com.zhihuishu.toolkit.jedis.JedisHelper;
import com.zhihuishu.toolkit.jedis.JedisHelper.Handler;
import com.zhihuishu.toolkit.jedis.template.JedisExecutor;

@Service("chapterService")
public class ChapterServiceImpl extends BaseServiceImpl<Chapter> implements ChapterService {

    @Resource
    private ChapterMapper chapterMapper;

    @Resource
    private LessonMapper lessonMapper;

    @Resource
    private LessonVideoMapper lessonVideoMapper;

    @Resource
    private CourseService courseService;

    @Resource
    private CourseBuildService courseBuildService;

    @Resource
    private IOnlineExamForCreateCourseService onlineExamForCreateCourseService;

   

    @Resource
    private JedisExecutor jedisExecutor;

    @Override
    public Integer create(ChapterDto chapter, long creator) {
        Assert.notNull(chapter, "章对象为空!");
        Assert.notNull(chapter.getCourseId(), "章所属课程ID为空!");
        Assert.notNull(chapter.getRank(), "章序号为空!");
        RemoteLogHelper.log(LogModule.CHAPTER_SAVE.getCode(), creator, "[开始]创建章[课程ID：{}/序号：{}]",
                chapter.getCourseId(), chapter.getRank());
        Chapter model = toModel(chapter);
        model.setPersonalCourseId(courseService.getLinkCourseId(chapter.getCourseId()));

        chapterMapper.insertSelective(model);

        Integer chapterId = model != null ? model.getId() : null;

        RemoteLogHelper.log(LogModule.CHAPTER_SAVE.getCode(), creator, "[完成]创建章[课程ID：{}/序号：{}]({})",
                chapter.getCourseId(), chapter.getRank(), chapterId);
        return chapterId;
    }

    private Chapter toModel(ChapterDto dto) {
        if (dto == null)
            return null;
        Chapter model = new Chapter();
        model.setDescription(dto.getDescription());
        model.setId(dto.getId());
        model.setLimitDay(dto.getLimitDay());
        model.setName(dto.getName());
        model.setOrderNumber(dto.getRank());
        model.setStudyHour(dto.getStudyHour());
        model.setPersonalCourseId(dto.getPersonalCourseId());
        model.setIsDeleted(dto.getIsDeleted());
        model.setCourseId(dto.getCourseId());
        model.setIsPass(dto.getIsPass());
        return model;
    }

    @Override
    public ChapterDto get(final Integer chapterId) {
        if (chapterId == null)
            return null;
        final List<ChapterDto> list = new ArrayList<ChapterDto>();
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                Set<String> sets = new HashSet<String>();
                sets.add(chapterId.toString());
                list.addAll(listFromRedis(jedis, sets));
            }
        });
        if (list.size() > 0) {
            return list.get(0);
        } else {
            return null;
        }
    }

    /**
     * Model转换DTO
     * 
     * @param model 章Model对象
     * @return
     */
    private ChapterDto toDto(Chapter model) {
        if (model == null)
            return null;
        ChapterDto dto = new ChapterDto();
        dto.setDescription(model.getDescription());
        dto.setId(model.getId());
        dto.setIsPass(model.getIsPass());
        dto.setLimitDay(model.getLimitDay());
        dto.setName(model.getName());
        dto.setRank(model.getOrderNumber());
        dto.setStudyHour(model.getStudyHour());

        // 课程ID需要使用TBL_COURSE主键
        if (model.getPersonalCourseId() != null) {
            dto.setCourseId(courseService.getByLinkId(model.getPersonalCourseId()));
        }
        return dto;
    }

    /**
     * 从Redis中根据主键列表，获取章哈希信息
     * 
     * @param jedis
     * @param chapterIds
     * @return
     */
    private List<ChapterDto> listFromRedis(Jedis jedis, Set<String> chapterIds) {
        Assert.notNull(jedis);
        Assert.notEmpty(chapterIds);
        List<ChapterDto> chapters = new ArrayList<ChapterDto>();
        Pipeline p = jedis.pipelined();
        // 使用管道，根据章ID列表，从Redis中查询章信息
        for (String chapterId : chapterIds) {
            p.hgetAll(JedisHelper.key("cc:chapter", chapterId));
        }
        List<Object> list = p.syncAndReturnAll();
        // 处理列表管道中获取的哈希列表
        Set<String> existSets = new HashSet<String>();
        if (!CollectionUtils.isEmpty(list)) {
            for (Object obj : list) {
                if (obj == null)
                    continue;
                @SuppressWarnings("unchecked")
                Map<String, String> hash = (Map<String, String>) obj;
                if (CollectionUtils.isEmpty(hash) || hash.get("id") == null)
                    continue;
                chapters.add(BeanHelper.transTo(hash, ChapterDto.class));
                existSets.add(hash.get("id")); // 如果缓存命中，记录之
            }
        }
        // 命中集合长度小于传入列表长度时，才需要执行touch操作
        if (existSets.size() < chapterIds.size()) {
            // 遍历命中集合，找出未命中部分，touch后放入列表中
            for (String chapterId : chapterIds) {
                if (!existSets.contains(chapterId)) {
                    ChapterDto dto = touchChapter(NumberUtils.toInt(chapterId));
                    if (dto != null)
                        chapters.add(dto);
                }
            }
        }
        return chapters;
    }

    @Override
    public List<ChapterDto> list(final long courseId) {
        final List<ChapterDto> chapters = new ArrayList<ChapterDto>();
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                // 缓存中获取课程下章列表
                String key = JedisHelper.key("cc:course", courseId, "chapters");
                Set<String> sets = jedis.smembers(key);
                if (CollectionUtils.isEmpty(sets)) {
                    // 未取到，更新缓存，并返回从数据库中查询得到的章ID列表
                    long tmpLinkCourseId = courseService.getLinkCourseId(courseId);
                    List<Integer> chapterIds = chapterMapper.list(tmpLinkCourseId);
                    // 如果非空，转换为字符串集合，后续统一处理
                    if (!CollectionUtils.isEmpty(chapterIds)) {
                        sets = new HashSet<String>();
                        for (Integer chapterId : chapterIds) {
                            if (chapterId == null)
                                continue;
                            sets.add(chapterId.toString());
                        }
                    }
                }
                // 从Redis中获取章列表
                if (sets != null && sets.size() > 0) {
                    chapters.addAll(listFromRedis(jedis, sets));
                }

            }
        });
        // 按rank值排序
        if (!CollectionUtils.isEmpty(chapters)) {
            Collections.sort(chapters, new Comparator<ChapterDto>() {
                @Override
                public int compare(ChapterDto o1, ChapterDto o2) {
                    if (o1 == null || o1.getRank() == null)
                        return 0;
                    if (o2 == null || o2.getRank() == null)
                        return 0;
                    return o1.getRank().compareTo(o2.getRank());
                }
            });
        }
        return chapters.isEmpty() ? null : chapters;
    }

    @Override
    public int chapterStudyDays(long courseId) {
        List<ChapterDto> list = this.list(courseId);
        if (CollectionUtils.isEmpty(list))
            return 0;
        int days = 0;
        for (ChapterDto dto : list) {
            if (dto.getLimitDay() != null)
                days += dto.getLimitDay();
        }
        return days;
    }

    /**
     * 从数据库中获取章对象
     * 
     * @param chapterId
     * @return
     */
    private ChapterDto getFromDb(int chapterId) {
        return toDto(chapterMapper.get(chapterId));
    }

    @Override
    public void touchChapter(final ChapterDto dto) {
        jedisExecutor.execute( new Handler() {

            @Override
            public void handle(Jedis jedis) {
                if (dto != null && dto.getId() != null) {
                    String key = JedisHelper.key("cc:chapter", dto.getId());

                    // 如果查到，转换为哈希结构并写入缓存
                    jedis.hmset(key, BeanHelper.describe(dto));

                }

            }
        });

    }

    @Override
    public ChapterDto touchChapter(final int chapterId) {
        final ChapterDto target = new ChapterDto();
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                String key = JedisHelper.key("cc:chapter", chapterId);
                // 数据库查询章
                ChapterDto dto = getFromDb(chapterId);
                if (dto != null && dto.getId() != null) {
                    jedis.del(key);// 先清除缓存(防止一些属性没有清除)
                    // 如果查到，转换为哈希结构并写入缓存
                    jedis.hmset(key, BeanHelper.describe(dto));
                    // 填充对象
                    BeanHelper.copyProperties(dto, target);
                }
            }
        });
        return target.getId() != null ? target : null;
    }

    @Override
    public void addChapterOnCourseRedis(final long courseId, final int chapterId) {
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                // System.out.println(JedisHelper.key("cc:course" ,courseId
                // ,"chapters")+"-------"+chapterId);

                jedis.sadd(JedisHelper.key("cc:course", courseId, "chapters"), String.valueOf(chapterId));
            }
        });
    }

    @Override
    public void removeChapterOnCourseRedis(final long courseId, final int chapterId) {
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                // System.out.println(JedisHelper.key("cc:course" ,courseId
                // ,"chapters")+"-------"+chapterId);
                jedis.srem(JedisHelper.key("cc:course", courseId, "chapters"), String.valueOf(chapterId));
            }
        });
    }

    @Override
    public List<Integer> listChapterId(final long courseId) {
        final List<Integer> list = new ArrayList<Integer>();
        jedisExecutor.execute( new Handler() {
            @Override
            public void handle(Jedis jedis) {
                // 缓存中获取课程下章列表
                String key = JedisHelper.key("cc:course", courseId, "chapters");
                Set<String> sets = jedis.smembers(key);
                if (CollectionUtils.isEmpty(sets)) {
                    list.addAll(chapterMapper.list(courseId));
                } else {
                    for (String chapterId : sets) {
                        if (chapterId != null)
                            list.add(NumberUtils.toInt(chapterId));
                    }
                }
            }
        });
        return list.isEmpty() ? null : list;
    }

    @Override
    public List<ChapterDto> findChaptersByCourseId(Long courseId) {
        if (courseId == null)
            return null;
        List<ChapterDto> chapterDtos = null;
        List<Chapter> chapters = chapterMapper.findChaptersByCourseId(courseId);
        if (!CollectionUtils.isEmpty(chapters)) {
            chapterDtos = new ArrayList<ChapterDto>();
            ChapterDto dto = null;
            for (Chapter model : chapters) {
                dto = new ChapterDto();
                dto.setId(model.getId());
                dto.setIsPass(model.getIsPass());
                dto.setRank(model.getOrderNumber());
                chapterDtos.add(dto);
            }
        }
        return chapterDtos;
    }

    @Override
    public int queryPassChapterCountByCourseId(long courseId) {
        Long ccCourseId = courseService.getLinkCourseId(courseId);
        Chapter chapter = new Chapter();
        chapter.setPersonalCourseId(ccCourseId);
        chapter.setIsDeleted(0);
        chapter.setIsPass(1);
        return chapterMapper.selectCount(chapter);

    }

    @Override
    public List<ChapterDto> getChapterListFromDb(Long courseId) {
        if (courseId == null)
            return null;
        List<ChapterDto> chapterDtos = null;
        List<Chapter> chapters = chapterMapper.getChapterListFromDb(courseId);
        if (!CollectionUtils.isEmpty(chapters)) {
            chapterDtos = new ArrayList<ChapterDto>();
            ChapterDto dto = null;
            for (Chapter model : chapters) {
                dto = new ChapterDto();
                dto.setId(model.getId());
                dto.setName(model.getName());
                dto.setRank(model.getOrderNumber());
                chapterDtos.add(dto);
            }
        }
        return chapterDtos;
    }

    @Override
    public void addChapterOnCourseRedisWithOutChecPassStatus(final long courseId, final int chapterId) {
        jedisExecutor.execute( new Handler() {

            @Override
            public void handle(Jedis jedis) {
                jedis.sadd(RedisKeyHelper.getCourseChapterAllKey(courseId), String.valueOf(chapterId));

            }
        });

    }

    @Override
    public void removeChapterOnCourseRedisWithOutChecPassStatus(final long courseId, final int chapterId) {
        jedisExecutor.execute( new Handler() {

            @Override
            public void handle(Jedis jedis) {
                jedis.srem(RedisKeyHelper.getCourseChapterAllKey(courseId), String.valueOf(chapterId));
            }
        });

    }

    @Override
    public Mapper<Chapter> getMapper() {
        return chapterMapper;

    }

    @Override
    public void saveChapterForApp(ChapterDto chapterDto) {
        Integer maxSort = chapterMapper.queryMaxChapterSortByCourseId(chapterDto.getCourseId());
        if (logger.isDebugEnabled()) {
            logger.debug("查询到课程{}下最大的章顺序为{}", chapterDto.getCourseId(), maxSort);
        }
        chapterDto.setRank(maxSort + 1);
        Chapter chapter = toModel(chapterDto);
        chapter.setUpdateTime(null);// 默认没有更新时间
        getMapper().insertSelective(chapter);
        chapterDto.setId(chapter.getId());
        touchChapter(chapterDto);
        // 新建章后 第三部变为不完整
        courseBuildService.updateCourseStepStat(chapterDto.getCourseId(), 3, 0);

    }

    @Override
    public List<Integer> queryIdsByCourseIdAndOredrNunber(Long courseId, Integer orderNumber) {
        return chapterMapper.queryIdsByCourseIdAndOredrNunber(courseId, orderNumber);

    }

    @Override
    public void updateMinusOrderNumByCourseIdAndOrderNumber(Long courseId, Integer orderNumber) {
        chapterMapper.updateMinusOrderNumByCourseIdAndOrderNumber(courseId, orderNumber);

    }

    @Override
    public List<Integer> queryChapterIdsContainSmallOrder(Long courseId, Integer orginRankBig,
            Integer targerRankSmall) {
        List<Integer> chapterIds = chapterMapper.queryChapterIdsContainSmallOrder(courseId, orginRankBig,
                targerRankSmall);
        chapterMapper.updateChapterIdsContainSmallOrder(courseId, orginRankBig, targerRankSmall);
        return chapterIds;

    }

    @Override
    public List<Integer> queryChapterIdsContainBigOrder(Long courseId, Integer orginRankSmall,
            Integer targerRankBig) {
        List<Integer> chapterIds = chapterMapper.queryChapterIdsContainBigOrder(courseId, orginRankSmall,
                targerRankBig);
        chapterMapper.updateChapterIdsContainBigOrder(courseId, orginRankSmall, targerRankBig);
        return chapterIds;
    }

    @Override
    public void deleteChapterById(Chapter chapter, Long courseId) {
        updateSelective(chapter);// 删除章

    }

    @Override
    public void updateChapterPassStatusAndStepStatus(Integer chapterId, Long courseId, long userId) {
        boolean passFlag = calcuteChapterPassStatus(chapterId);
        if (logger.isDebugEnabled()) {
            logger.debug("查询章{}是否通过审核{}",chapterId,passFlag);
        }
        if (passFlag) {// 通过
            updateChapterPassStatus(chapterId, 1);// 通过
            Chapter chapter = new Chapter();
            chapter.setCourseId(courseId);
            chapter.setIsDeleted(0);
            chapter.setIsPass(0);
            Integer unpassChapterCount = chapterMapper.selectCount(chapter);// 查询未通过审核章的数量
            if (logger.isDebugEnabled()) {
                logger.debug("查询到课程{}未通过的章的数量为{}",courseId,unpassChapterCount);
            }
            if (unpassChapterCount > 0) {// 有存在未通过的章
                courseBuildService.updateCourseStepStat(courseId, 3, 0);
                return;
            }
            boolean hasCourseExamFalg = false;
            List<ExamCourseDto> courseDtos = onlineExamForCreateCourseService
                    .listExamCourseForCreateCourse(courseId.intValue());
            if (courseDtos != null && courseDtos.size() > 0) {
                for (ExamCourseDto examCourseDto : courseDtos) {
                    if (examCourseDto != null && examCourseDto.getType() != null
                            && examCourseDto.getType() == 1) {// 教程试卷
                        hasCourseExamFalg = true;// 有教程试卷
                    }
                }
            }
            if (hasCourseExamFalg) {// 有教程试卷
                courseBuildService.updateCourseStepStat(courseId, 3, 1);// 第三步未通过
            } else {// 没有教程试卷
                courseBuildService.updateCourseStepStat(courseId, 3, 0);// 第三步未通过
            }

        } else {// 未通过
            updateChapterPassStatus(chapterId, 0);
            courseBuildService.updateCourseStepStat(courseId, 3, 0);// 第三步未通过
        }

    }

    private void updateChapterPassStatus(Integer chapterId, int passFlag) {
        Chapter  temp = getMapper().selectByPrimaryKey(chapterId);
        if (temp.getIsDeleted().equals(0)) {//只有未删除的章才进行更新
            Chapter chapter = new Chapter();
            chapter.setId(chapterId);
            chapter.setIsPass(passFlag);
            chapter.setUpdateTime(new Date());
            getMapper().updateByPrimaryKeySelective(chapter);
        }
       

    }

    private boolean calcuteChapterPassStatus(Integer chapterId) {

        // 章 名称 描述 考试
        Chapter chapter = chapterMapper.selectByPrimaryKey(chapterId);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到章{}的信息为{}", chapterId,chapter);
        }
        if (chapter == null) {
            return false;
        }
        if (chapter.getIsDeleted().equals(1)) {//已经删除的章 则默认为通过了
            return true;
        }
        
        if (chapter.getName() == null || chapter.getDescription() == null) {// 名称或者简介为空(不通过)
            return false;
        }
        boolean hasTest = onlineExamForCreateCourseService.queryChapterHasTest(chapterId);
        if (!hasTest) {// 没有章测试
            return false;
        }
        // 节 名称 简介 主讲人 知识点 是否含有小节 视频id
        List<Lesson> lessons = lessonMapper.selectInfoForCompCheck(chapterId);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到节的信息为{}", lessons);
        }
        if (lessons != null && lessons.size() > 0) {
            for (Lesson lesson : lessons) {
                if (lesson.getName() == null || lesson.getIntroduction() == null
                        || StringUtils.isEmpty(lesson.getSpeaker()) || lesson.getHasKnowledegPoint() == 0) {
                    return false;
                }
                if (lesson.getIsHaveChildrenLesson() == null || lesson.getIsHaveChildrenLesson() == 0) {// 没有子小节
                    if (lesson.getVideoId() == null) {// 没有子节 却没有视频id
                        return false;
                    }
                }
            }
        } else {// 章下面没有小节
            return false;
        }
        // 小节(视频 知识点 主讲人)
        List<LessonVideo> lessonVideos = lessonVideoMapper.selectInfoForCompCheck(chapterId);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到小节的信息为{}", lessonVideos);
        }
        if (lessonVideos != null && lessonVideos.size() > 0) {
            for (LessonVideo lessonVideo : lessonVideos) {
                if (lessonVideo.getVideoId() == null || lessonVideo.getHasKnowledegPoint() == 0
                        || StringUtils.isEmpty(lessonVideo.getSpeaker())) {
                    return false;
                }
            }
        }
        return true;

    }

    @Override
    public Set<String> queryPassChapterIdsByCourseIdAndAddToCache(final long courseId) {
        final List<Integer> chapterIds = chapterMapper.queryChapterIdsByCourseId(courseId, 1);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到章的ids为{}", chapterIds);
        }
        if (CollectionUtils.isEmpty(chapterIds)) {
            return Sets.newHashSetWithExpectedSize(0);
        }
        String key = JedisHelper.key("cc:course", courseId, "chapters");
        addChapterIdsToCache(key, chapterIds);
        addChapterInfoIntoCache(chapterIds);
        Set<String> strings=Sets.newHashSet(); 
        for (Integer temp : chapterIds) {
            strings.add(temp.toString());
        }
        return strings;
    }

    private void addChapterInfoIntoCache(List<Integer> chapterIds) {// 章数据添加到缓存中
        if (CollectionUtils.isEmpty(chapterIds)) {
            return ;
        }
        final List<Chapter> chapters = chapterMapper.getByIds(chapterIds);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到的章数据为{}", chapters);
        }
        if (!CollectionUtils.isEmpty(chapterIds)) {
            jedisExecutor.execute( new Handler() {

                @Override
                public void handle(Jedis jedis) {
                    Pipeline pipelined = jedis.pipelined();
                    String key;
                    Map<String, String> map;
                    for (Chapter chapter : chapters) {
                        key = JedisHelper.key("cc:chapter",chapter.getId());
                        map = BeanHelper.describe(toDto(chapter));                      
                        pipelined.hmset(key, map);
                    }
                    for (int i = 0; i < chapters.size(); i++) {
                      
                       
                    }
                    pipelined.sync();

                }
            });
        }
    

    }

    private void addChapterIdsToCache(final String key, final List<Integer> chapterIds) {// 章id添加到缓存中
        if (CollectionUtils.isEmpty(chapterIds)) {
            return;
        }
        final String[] chapterIdArr = new String[chapterIds.size()];
        for (int i = 0; i < chapterIds.size(); i++) {
            chapterIdArr[i] = chapterIds.get(i).toString();
        }
        jedisExecutor.execute( new Handler() {

            @Override
            public void handle(Jedis jedis) {
                jedis.del(key);
                jedis.sadd(key, chapterIdArr);

            }
        });
    
    }

    @Override
    public Set<String> queryChapterIdsByCourseIdAndAddToCache(Long courseId) {
        List<Integer> chapterIds = chapterMapper.queryChapterIdsByCourseId(courseId, null);
        if (logger.isDebugEnabled()) {
            logger.debug("查询到章的ids为{}", chapterIds);
        }
        if (CollectionUtils.isEmpty(chapterIds)) {
            return Sets.newHashSetWithExpectedSize(0);
        }
        String key = JedisHelper.key("cc:course", courseId, "chapters:all");
        addChapterIdsToCache(key, chapterIds);// 章id添加到缓存中
        
        addChapterInfoIntoCache(chapterIds);// 章详情添加到缓存中
        Set<String> strings=Sets.newHashSet(); 
        for (Integer temp : chapterIds) {
            strings.add(temp.toString());
        }
        return strings;
        
    }

}
